package com.jingbit.ai.utils;


import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.hardware.Camera;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.view.SurfaceView;

import com.baidu.idl.main.facesdk.FaceInfo;
import com.google.gson.reflect.TypeToken;
import com.jingbit.ai.AIApp;
import com.jingbit.ai.R;
import com.jingbit.ai.activity.FaceActivity;
import com.jingbit.ai.bean.UserInfo;
import com.jingbit.ai.helper.GJsonHelper;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfFloat;
import org.opencv.core.MatOfInt;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.core.TermCriteria;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.ml.EM;
import org.opencv.objdetect.CascadeClassifier;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;

public class FaceUtil {

    private Vector<UserInfo> registers;
    public static int detectFrequency = 60;

    public FaceUtil(Context context) {
        registers = new Vector<>();
        String sregister = SharedPrefsUtil.getValue(context, AIApp.TAG, "registers", "");
        List<UserInfo> users = GJsonHelper.parseJsonArray(sregister, new TypeToken<List<UserInfo>>() {
        }.getType());
        if (users != null) {
            for (UserInfo userInfo : users) {
                registers.add(userInfo);
            }
        }
    }

    public void addFace(Context context, String name, FaceInfo faceInfo) {
        UserInfo exist = null;
        for (UserInfo userInfo : registers) {
            float[] landmarks2 = userInfo.landmarks;
            double ret = calculateCosineSimilarity(faceInfo.landmarks, landmarks2);
            Log.d(AIApp.TAG, "addFace: " + ret + "---" + detectFrequency);
            if (ret >= 0.75) {
                exist = userInfo;
                break;
            }
        }
        if (exist != null) {
            return;
        }
        UserInfo userInfo = new UserInfo(faceInfo.faceID, faceInfo.landmarks, name, faceInfo.age, faceInfo.gender);
        userInfo.setTimestamp(System.currentTimeMillis());
        registers.add(userInfo);
        if (!TextUtils.isEmpty(name)) {
            SharedPrefsUtil.putValue(context, AIApp.TAG, "registers", GJsonHelper.toJson(registers));
        }
    }

    public void clearFace() {
        List<UserInfo> temps = new ArrayList<>();
        for (UserInfo userInfo : registers) {
            if (!TextUtils.isEmpty(userInfo.getName())) {
                continue;
            }
            int timeGap = (int) ((System.currentTimeMillis() - userInfo.getTimestamp()) / 1000);
            Log.d(AIApp.TAG, "clearFace: " + timeGap);
            if (timeGap > detectFrequency) {
                temps.add(userInfo);
            }
        }
        for (UserInfo userInfo : temps) {
            registers.remove(userInfo);
        }
        temps.clear();
    }

    public void resetFace(UserInfo userInfo) {
        userInfo.setTimestamp(System.currentTimeMillis());
        int index = registers.indexOf(userInfo);
        registers.set(index, userInfo);
    }

    public UserInfo doCompare(float[] landmarks1, double threshold) {
        if (registers.isEmpty()) {
            return null;
        }
        for (UserInfo userInfo : registers) {
            float[] landmarks2 = userInfo.landmarks;
            double ret = calculateCosineSimilarity(landmarks1, landmarks2);
            Log.d(AIApp.TAG, "doCompare: " + ret + "---" + detectFrequency);
            if (ret >= threshold) {
                return userInfo;
            }
        }
        return null;
    }

    public double calculateEuclideanDistance(float[] keypoints1, float[] keypoints2) {
        double sum = 0.0;
        for (int i = 0; i < keypoints1.length; i++) {
            double diff = keypoints1[i] - keypoints2[i];
            sum += Math.pow(diff, 2);
        }
        return Math.sqrt(sum);
    }

    public double calculateCosineSimilarity(float[] keypoints1, float[] keypoints2) {
        double dotProduct = 0.0;
        double norm1 = 0.0;
        double norm2 = 0.0;

        for (int i = 0; i < keypoints1.length; i++) {
            dotProduct += keypoints1[i] * keypoints2[i];
            norm1 += Math.pow(keypoints1[i], 2);
            norm2 += Math.pow(keypoints2[i], 2);
        }

        return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
    }

}

